package com.aplink.generic.webservice;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
import java.util.ArrayList;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONException;

import android.os.AsyncTask;

import com.aplink.generic.GenericFragment;
import com.aplink.generic.cache.MasterConfigManager;
import com.aplink.generic.constant.WebServiceContant;
import com.aplink.generic.constant.type.ActionType;
import com.aplink.generic.constant.type.DialogStatus;
import com.aplink.generic.interfaces.OnHttpTaskPostExcute;
import com.aplink.generic.util.LogUtil;

public class HttpTask extends AsyncTask<HttpURL, Void, ArrayList<DataResult>> {
	public static int CONNECTION_TIME_OUT = 10000;
	public static int SO_TIME_OUT = 10000;
	private WeakReference<GenericFragment> mFragment;
	private OnHttpTaskPostExcute mHttpTaskPostExcute;
	private int mTaskSize = 0;
	private final ActionType mTaskType;

	public HttpTask(final ActionType actionType) {
		this.mTaskType = actionType;
	}

	public HttpTask(final GenericFragment fragment, final ActionType taskType) {
		this.mFragment = new WeakReference<GenericFragment>(fragment);
		this.mTaskType = taskType;
	}

	@Override
	protected ArrayList<DataResult> doInBackground(final HttpURL... params) {
		final ArrayList<DataResult> results = new ArrayList<DataResult>();
		this.mTaskSize = params.length;
		for (final HttpURL url : params) {
			results.add(excuteRequest(url));
		}
		return results;
	}

	private DataResult excuteRequest(final HttpURL genericUrl) {
		try {
			DataResult dataResult = new DataResult();
			final HttpParams httpParameters = new BasicHttpParams();
			HttpConnectionParams.setConnectionTimeout(httpParameters,
			        HttpTask.CONNECTION_TIME_OUT);
			HttpConnectionParams.setSoTimeout(httpParameters,
			        HttpTask.SO_TIME_OUT);
			final HttpClient httpClient = new DefaultHttpClient(httpParameters);
			HttpUriRequest request = null;
			genericUrl.setActionType(mTaskType);
			if (genericUrl.getMethod() == WebServiceContant.POST) {
				final HttpPost httppost = new HttpPost(
				        genericUrl.getWebserviceURL());
				httppost.setEntity(genericUrl.getHttpPostData());
				request = httppost;
			} else {
				request = new HttpGet(genericUrl.getWebserviceURL());
			}
			final int tryTime = MasterConfigManager.getInstance().get()
			        .getTryTime();
			final HttpResponse response = requestToServer(httpClient, request,
			        tryTime, genericUrl);
			final StatusLine statusLine = response.getStatusLine();
			final HttpResponseStatus statusCode = HttpResponseStatus
			        .get(statusLine.getStatusCode());
			final HttpEntity entity = response.getEntity();
			final InputStream content = entity.getContent();
			final BufferedReader reader = new BufferedReader(
			        new InputStreamReader(content));
			String line;
			final StringBuilder stringBuilder = new StringBuilder();
			while ((line = reader.readLine()) != null) {
				stringBuilder.append(line);
			}
			String result = stringBuilder.toString().replace(
			        "<?xml version=\"1.0\" encoding=\"utf-8\"?>", "");
			result = result.replace("<string xmlns=\"http://aplink.com.sg/\">",
			        "");
			result = result.replace("<string xmlns=\"http://tempuri.org/\">",
			        "");
			result = result.replace("</string>", "");
			LogUtil.info(LogUtil.TAG_WEBSERVICE, result, "Webservice response",
			        getClass());
			if (statusCode.equals(HttpResponseStatus.SUCCESS)) {
				if (this.mTaskType.isIgnoreWebservice()) {
					dataResult = WebServiceParser.getInstance().parse(result,
					        genericUrl.initTableName(),
					        genericUrl.getContentData());
				} else {
					dataResult = WebServiceParser.getInstance().parse(result,
					        genericUrl.getContentData(),
					        this.mFragment.get().getMappingObject());
				}
				reader.close();
			}
			dataResult.setTable(genericUrl.initTableName());
			dataResult.setStatusCode(statusCode);
			dataResult.setObjPropCol(genericUrl.getContentData());
			dataResult.setGenericObject(genericUrl.getGenericObject());
			return dataResult;
		} catch (final IOException e) {
			LogUtil.error(LogUtil.TAG_WEBSERVICE, String.format(
			        "Can't open connection to: %s. The connection was aborted",
			        genericUrl.toString()), "excute Get Request", getClass());

		} catch (final JSONException e) {
			LogUtil.error(LogUtil.TAG_WEBSERVICE,
			        "Can not creates a new JSONArray with values ",
			        "excute Get Request", getClass());
		}
		return DataResult.obtain(null, HttpResponseStatus.UNKNOW_ERROR);
	}

	public OnHttpTaskPostExcute getHttpTaskPostExcute() {
		return this.mHttpTaskPostExcute;
	}

	@Override
	protected void onPostExecute(final ArrayList<DataResult> result) {
		super.onPostExecute(result);
		if (this.mHttpTaskPostExcute == null) {
			if (this.mFragment.get() != null) {
				if (result.isEmpty() && (this.mTaskSize == 0)) {
					if (this.mTaskType.equals(ActionType.UPLOAD)) {
						if (this.mFragment.get().hasRegisterProgressDialog(
						        ActionType.UPLOAD)) {
							this.mFragment.get()
							        .getProgressDialog(ActionType.UPLOAD)
							        .dismiss();
						}
						this.mFragment.get().getAlertDialog()
						        .show(this.mTaskType, DialogStatus.SUCCESSFUL);
					}
				} else {
					this.mFragment.get().getResponseHandler()
					        .obtainMessage(this.mTaskType.getCode(), result)
					        .sendToTarget();
				}
			}
		} else {
			this.mHttpTaskPostExcute.onPostExecute(result);
		}
	}

	private HttpResponse requestToServer(final HttpClient httpClient,
	        final HttpUriRequest request, final int tryTime,
	        final HttpURL genericUrl) throws IOException {
		int i = 1;
		boolean hasError = true;
		IOException e = null;
		while ((i < tryTime) && hasError) {
			try {
				final String message = String.format(i
				        + ": Connect to server: %s", genericUrl.toString());
				LogUtil.info(LogUtil.TAG_WEBSERVICE, message,
				        "requestToServer", getClass());
				final HttpResponse response = httpClient.execute(request);
				hasError = false;
				return response;
			} catch (final IOException ex) {
				hasError = true;
				e = ex;
			}
			i++;
		}
		if (hasError) {
			throw e;
		}
		return null;
	}

	public void setHttpTaskPostExcute(
	        final OnHttpTaskPostExcute httpTaskPostExcute) {
		this.mHttpTaskPostExcute = httpTaskPostExcute;
	}
}
